package com.joysuch.wwyt.bp.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.zlg.common.enums.BusinessTypeEnum;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.yitter.idgen.YitIdHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.joysuch.wwyt.alert.service.NoticeWaitingTriggerListService;
import com.joysuch.wwyt.app.bean.AppInvestigateRecordDto;
import com.joysuch.wwyt.bp.bean.BpBaseUserBean;
import com.joysuch.wwyt.bp.bean.PositionCheckBean;
import com.joysuch.wwyt.bp.bean.bo.PositionCheckBO;
import com.joysuch.wwyt.bp.bean.investigate.*;
import com.joysuch.wwyt.bp.bean.investigate.vo.BpInvestigateRecordItemVO;
import com.joysuch.wwyt.bp.bean.investigate.vo.BpInvestigateRecordVO;
import com.joysuch.wwyt.bp.bean.investigate.vo.TaskItemMapperVo;
import com.joysuch.wwyt.bp.constant.AppNotifyContentPre;
import com.joysuch.wwyt.bp.constant.AppNotifyContentSuf;
import com.joysuch.wwyt.bp.constant.InvestigateConfigNames;
import com.joysuch.wwyt.bp.entity.BpDepart;
import com.joysuch.wwyt.bp.entity.BpInvestigateTaskAssign;
import com.joysuch.wwyt.bp.entity.BpInvestigateTaskSummary;
import com.joysuch.wwyt.bp.entity.BpInvestigateTaskSummaryHis;
import com.joysuch.wwyt.bp.entity.bean.SummaryToUpDateBean;
import com.joysuch.wwyt.bp.entity.dto.BpInvestigateRecordItemDto;
import com.joysuch.wwyt.bp.entity.dto.DeleteInvestigateRecordDto;
import com.joysuch.wwyt.bp.entity.dto.UserTaskRecordDto;
import com.joysuch.wwyt.bp.entity.investigate.*;
import com.joysuch.wwyt.bp.enums.*;
import com.joysuch.wwyt.bp.mapper.*;
import com.joysuch.wwyt.bp.repository.*;
import com.joysuch.wwyt.bp.service.*;
import com.joysuch.wwyt.common.constant.Constant;
import com.joysuch.wwyt.common.entity.CommonBusinessNotice;
import com.joysuch.wwyt.common.entity.CommonIndexNotify;
import com.joysuch.wwyt.common.enums.AppBusinessNoticeTypes;
import com.joysuch.wwyt.common.enums.CommonIndexNotifyTypes;
import com.joysuch.wwyt.common.repository.CommonIndexNotifyDao;
import com.joysuch.wwyt.common.service.CommonBusinessNoticeService;
import com.joysuch.wwyt.config.RedisClient;
import com.joysuch.wwyt.core.bean.BaseAttachmentBean;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.common.util.JsonUtil;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.common.util.SimpleDateFormatCache;
import com.joysuch.wwyt.core.entity.BaseConfig;
import com.joysuch.wwyt.core.entity.BaseUser;
import com.joysuch.wwyt.core.enums.BaseConfigCodes;
import com.joysuch.wwyt.core.enums.DeleteFlag;
import com.joysuch.wwyt.core.enums.Status;
import com.joysuch.wwyt.core.exception.ApiCoreException;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.security.ShiroUser;
import com.joysuch.wwyt.core.service.BaseConfigService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.mh.enums.ExceptionHandleEnum;
import com.joysuch.wwyt.risk.bean.FencePoint;
import com.joysuch.wwyt.risk.entity.RiskEvaluationControl;
import com.joysuch.wwyt.risk.entity.RiskPoint;
import com.joysuch.wwyt.risk.entity.vo.RiskItemEvalCountRecordVo;
import com.joysuch.wwyt.risk.enums.ControlRiskLevelType;
import com.joysuch.wwyt.risk.repository.RiskPointDao;
import com.joysuch.wwyt.risk.service.RiskEvaluationBusinessService;
import com.joysuch.wwyt.risk.service.RiskEvaluationTempleService;
import com.joysuch.wwyt.risk.service.RiskPointService;
import com.joysuch.wwyt.util.FileUtil;
import com.joysuch.wwyt.util.PoiUtil;
import com.joysuch.wwyt.util.RegionUtil;
import com.joysuch.wwyt.util.StringUtil;
import com.joysuch.wwyt.workflow.api.bean.TrajectoryLastLocationResp;
import com.joysuch.wwyt.workflow.api.service.impl.PersonTrajectoryImpl;
import com.joysuch.wwyt.workflow.enums.LocationVerifyStateEnum;
import com.joysuch.wwyt.workflow.repository.WorkFlowTaskDao;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.querydsl.QPageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author ZhangDong
 * @Date 2020/3/26 9:35
 */
@Service
@Slf4j
public class BpInvestigateRecordServiceImpl implements BpInvestigateRecordService {

    @Autowired
    private BpInvestigateRecordRepository recordRepository;

    @Autowired
    private BpInvestigatePlanService planService;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpDepartDao bpDepartDao;
    @Autowired
    private BpInvestigatePlanRepository planRepository;
    @Autowired
    private BpSafeTableItemDao tableItemDao;
    @Autowired
    private BpInvestigateRecordItemDao recordItemDao;
    @Autowired
    private BpInvestigateTaskDao taskDao;
    @Autowired
    private CommonIndexNotifyDao commonIndexNotifyDao;
    @Autowired
    private WorkFlowTaskDao workFlowTaskDao;
    @Autowired
    private BpInvestigateTaskAssignService bpInvestigateTaskAssignService;
    @Autowired
    private BpInvestigateTaskSummaryMapper summaryMapper;
    @Autowired
    private BpInvestigateTaskSummaryService bpInvestigateTaskSummaryService;
    @Autowired
    private BpInvestigateTaskSummaryHisService summaryHisService;
    @Autowired
    private PersonTrajectoryImpl personTrajectory;
    @Autowired
    private RiskPointDao riskPointDao;
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private RiskEvaluationBusinessService evaluationBusinessService;
    @Autowired
    private BaseConfigService baseConfigService;
    @Autowired
    private InspectExceptionAlarmMesageService inspectExceptionAlarmMesageService;
    @Autowired
    private BpInvestigateRecordItemDao bpInvestigateRecordItemDao;
    @Autowired
    private BpInvestigateVerifyLogService verifyLogService;
    @Autowired
    private InspectExceptionAlarmMesageMapper inspectExceptionAlarmMesageMapper;
    @Autowired
    private RiskPointService riskPointService;
    @Autowired
    private CommonBusinessNoticeService commonBusinessNoticeService;
    @Autowired
    private NoticeWaitingTriggerListService noticeWaitingTriggerListService;
    @Autowired
    private BpInvestigateRecordItemMapper recordItemMapper;
    @Autowired
    private BpInvestigateTaskHisMapper investigateHistoryMapper;
    @Resource
    private BpInvestigateConfigService investigateConfigService;
    @Autowired
    private RiskEvaluationTempleService riskEvaluationTempleService;
    @Autowired
    private BpInvestigateRecordMapper bpInvestigateRecordMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultBean save(BpInvestigateRecordBean bean) {
        //app上传之前，排查计划删除了，则无需记录，返回错误信息即可
        Long planId = bean.getCheckPlanId();
        BpInvestigatePlan plan = planRepository.findById(planId).orElseThrow(() -> new IllegalArgumentException("排查计划已删除"));
        Long id = bean.getId();
        List<BpInvestigateRecordItemBean> itemBeanList = bean.getItemBeanList();
        BpInvestigateRecord record;
        if (id == null) {
            record = new BpInvestigateRecord();
        } else {
            record = recordRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("此数据不存在"));
        }
        BeanUtils.copyProperties(bean, record);
        if (record.getId() == null){
            record.setId(YitIdHelper.nextId());
        }
        //参与人员
        if (!CollectionUtils.isEmpty(bean.getParticipants())) {
            record.setParticipants(JSON.toJSONString(bean.getParticipants()));
        } else {
            record.setParticipants(null);
        }
        record.setSourceType(SourceType.OLD.getValue());
        record = recordRepository.save(record);
        Long recordId = record.getId();
        //检查项目
        if (!CollectionUtils.isEmpty(itemBeanList)) {
            for (BpInvestigateRecordItemBean itemBean : itemBeanList) {
                if ("异常".equals(itemBean.getAction())) {
                    setRecordResult(record, "异常");
                    itemBean.setRepairStatus("未整改");
                } else if ("未检".equals(itemBean.getAction())) {
                    setRecordResult(record, "未检");
                    itemBean.setRepairStatus("无需整改");
                } else {
                    itemBean.setRepairStatus("无需整改");
                }
                //保存数据
                BpInvestigateRecordItem recordItem = new BpInvestigateRecordItem();
                BeanUtils.copyProperties(itemBean, recordItem);
                if (recordItem.getId() == null){
                    recordItem.setId(YitIdHelper.nextId());
                }
                List<BaseAttachmentBean> attachmentList = itemBean.getAttachmentList();
                recordItem.setAttachmentJson(attachmentList == null ? null : JSON.toJSONString(attachmentList));
                recordItem.setRecordId(recordId);
                recordItemDao.save(recordItem);
            }
        }
        if (StringUtils.isEmpty(record.getCheckResult())) {
            record.setCheckResult("正常");
        }
        recordRepository.save(record);
        //任务处理
        Long taskId = bean.getTaskId();
        //InvestigateTaskStatus
        BpInvestigateTask task = null;
        if (taskId != null) {
            //任务一人完成即可,多人提交保留最后一条记录
            task = taskDao.findById(taskId).orElseThrow(() -> new IllegalArgumentException("任务已删除"));
            boolean repeatCommit = (InvestigateTaskStatus.DONE.getStatus().equals(task.getStatus()) ||
                    InvestigateTaskStatus.OVERDUE.getStatus().equals(task.getStatus())) && task.getRecordId() != null;
            if (repeatCommit) {
                throw new IllegalArgumentException("重复提交");
            }
            //同任务包含自身
            List<BpInvestigateTask> taskList = taskDao.findByPlanIdAndCheckDate(task.getPlanId(), task.getCheckDate());
            boolean after = false;
            // 被定时任务刷成'未完成'的，提交后设置为'逾期完成'
            after = InvestigateTaskStatus.NO.getStatus().equals(task.getStatus());
            List<Long> needSubRecordIds = Lists.newArrayList();
            if (taskList.size() == 1) {
                task.setStatus(after ? InvestigateTaskStatus.OVERDUE.getStatus() : InvestigateTaskStatus.DONE.getStatus());
                task.setRecordId(recordId);
                task.setFinishDate(new Date());
                taskDao.save(task);
            }
            //多人任务
            else if (taskList.size() > 1) {
                //删除之前提交过的记录
                needSubRecordIds = taskList.stream().filter(r -> InvestigateTaskStatus.DONE.getStatus().equals(r.getStatus())
                        || InvestigateTaskStatus.OVERDUE.getStatus().equals(r.getStatus())).map(r -> r.getRecordId()).
                        filter(Objects::nonNull).collect(Collectors.toList());
                for (Long tempId : needSubRecordIds) {
                    recordRepository.deleteById(tempId);
                }
                taskList.forEach(r -> {
                    r.setStatus("被完成");
                    r.setRecordId(null);
                    taskDao.save(r);
                });
                task.setStatus(after ? InvestigateTaskStatus.OVERDUE.getStatus() : InvestigateTaskStatus.DONE.getStatus());
                task.setRecordId(recordId);
                task.setFinishDate(new Date());
                taskDao.save(task);
            }
            try {
                // 删除其他人task_assign数据
                List<Long> taskIds = taskList.stream().map(BpInvestigateTask::getId).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(taskIds)) {
                    bpInvestigateTaskAssignService.deleteByTaskIdsAndUserIdNe(taskIds, Context.getCurrentUserId());
                }
            } catch (Exception e) {
                log.error("删除隐患排查任务异常: taskId: {}, {}", taskId, e.getMessage());
            }
            updateSummaryStat(taskList, record.getCheckResult(), after, needSubRecordIds);
        }
        //异常消息通知  目前此模块没有未检
        exceptionNotify(record, plan);
        //异常需要推送报警信息
        if ("异常".equals(record.getCheckResult())) {
            try {
                inspectExceptionAlarmMesageService.saveMessage(planId, bean.getCheckUserId(), AlarmContentTypes.INVESTIGATE_FIND_EXCEPTION.getCode(), Context.getCurrentTenantId(), Context.getCurrentOrgCode());
                // app消息中心
                generateAppNotifyForOld(task, planId, bean.getCheckUserId());
            } catch (Exception e) {
                log.error("巡检报警/消息推送错误" + e);
            }
        }
        return ResultBean.success(recordId);
    }


    /**
     * @param checkResult
     * @param after
     */
    private void updateSummaryStat(List<BpInvestigateTask> taskList, String checkResult, boolean after, List<Long> needSubRecordIds) {
        Set<Long> taskIds = taskList.stream().map(BpInvestigateTask::getId).collect(Collectors.toSet());
        // 以下各计数累加时可直接置为1，计划性隐患排查一条汇总下只有一条任务
        Long userId = Context.getCurrentUserId();
        if (after) {
            // 逾期完成数累加
            summaryMapper.updateSummaryTimeOutCheckCount(taskIds);
        } else {
            // 完成人任务完成数 +1
            summaryMapper.updateSummaryTaskDoneCount(taskIds, userId);
            if (!StringUtils.isEmpty(checkResult) && checkResult.contains("正常")) {
                // 检查结果: 正常 非完成人 任务数 -1
                summaryMapper.updateSummaryTaskCount(taskIds, userId);
            }
        }
        if (!StringUtils.isEmpty(checkResult)  && checkResult.contains("异常")) {
            // 完成人发现异常数 +1
            summaryMapper.updateSummaryExceptionCountAndStatus(taskIds, userId);
            // 非完成人 任务数 -1
            summaryMapper.updateSummaryTaskCount(taskIds, userId);
        } else {
            summaryMapper.updateSummaryExceptionStatus(taskIds, ExceptionHandleEnum.NO_NEED_HANDLE.getDesc());
        }
        // 设置完成人、完成时间、完成状态
        summaryMapper.updateSummaryCompleteDateAndResult(taskIds, Context.getCurrentUserId(), new Date(), checkResult);
        taskList.forEach(task -> {
            summaryMapper.updateSummaryStatus(task.getId(), task.getStatus());
        });
        // 删除了完成任务记录, 需要相应的删除summary数据
        if (!CollectionUtil.isEmpty(needSubRecordIds)) {
            List<BpInvestigateRecord> records = bpInvestigateRecordMapper.getListByIds(needSubRecordIds);
            if (!CollectionUtil.isEmpty(records)) {
                records.forEach(record -> {
                    if (record.getTaskId() != null && record.getCheckUserId() != null && record.getCheckUserId() != -1) {
                        summaryMapper.subSummaryTaskDoneCount(record.getTaskId(), record.getCheckUserId());
                        summaryMapper.subHisSummaryTaskDoneCount(record.getTaskId(), record.getCheckUserId());
                        if ("异常".equals(record.getCheckResult())) {
                            summaryMapper.subSummaryExceptionCount(record.getTaskId(), record.getCheckUserId());
                            summaryMapper.subHisSummaryExceptionCount(record.getTaskId(), record.getCheckUserId());
                        }
                    }
                });
            }
        }
    }

    ;

    @Override
    public List<TaskItemMapperVo> saveBatch(List<BpInvestigateRecordVO> records) {
        //key:评估步骤id value:评估计划id集合
        List<TaskItemMapperVo> taskItemMapperVoList = new ArrayList<>();
        for (BpInvestigateRecordVO recordVo : records) {
            TaskItemMapperVo vo = new TaskItemMapperVo();
            Long taskId = recordVo.getTaskId();
            vo.setItemId(saveV2(recordVo));
            vo.setTaskId(taskId);
            taskItemMapperVoList.add(vo);
        }
        return taskItemMapperVoList;
    }

    @Override
    public Long saveV2(BpInvestigateRecordVO recordVO) {
        Long id = recordVO.getId();
        BpInvestigateRecordItemVO itemVO = recordVO.getRecordItem();
        Long taskId = recordVO.getTaskId();
        // app端提交的，比对是否超出巡检时间
        if (taskId != null && !StringUtil.isEmpty(recordVO.getVerifyType())) {
            Optional<BpInvestigateTask> optionalTask = taskDao.findById(taskId);
            optionalTask.ifPresent(bpInvestigateTask -> Assert.isTrue(bpInvestigateTask.getDeadline().getTime() >= System.currentTimeMillis(), Status.CHECK_TIME_OUT.getMsg()));
        }
        BpInvestigateRecord record = recordRepository.findFirstByTaskIdAndSourceType(taskId, SourceType.NEW.getValue());
        if (record != null && recordVO.getRecordItem().getId() == null) {
            // task下已有记录，但本次提交无itemId，表示此次提交为滞留页面提交，滞留期间任务已被他人提交
            throw new IllegalArgumentException(Status.CURRENT_TASK_HAD_HANDLE.getMsg());
        }
        if (record == null) {
            record = id == null ? new BpInvestigateRecord().setId(YitIdHelper.nextId()) : recordRepository.findById(id).isPresent() ? recordRepository.findById(id).get() : new BpInvestigateRecord().setId(YitIdHelper.nextId());
            record.setTaskId(taskId);
            record.setSourceType(SourceType.NEW.getValue());
        }
        record.setCheckPlanId(recordVO.getCheckPlanId());
        String checkResult = itemVO.getAction();
        // web端提交未检任务，去掉未检原因
        if (checkResult.startsWith(RecordActionType.UC.getValue())) {
            checkResult = RecordActionType.UC.getValue();
        }
        if (checkResult.contains(Constant.EN_LEFT_BRACKETS)) {
            checkResult = checkResult.substring(0, 2);
        }
        record.setCheckResult(checkResult);
        record.setCheckFinishDate(itemVO.getCheckFinishDate() != null ? itemVO.getCheckFinishDate() : new Date());
        record.setCheckUserId(Context.getCurrentUserId());
        // 签到信息(web提交时没有签到信息)
        if (recordVO.getVerifyType() != null) {
            record.setVerifyLocation(recordVO.getVerifyLocation());
            record.setVerifyState(recordVO.getVerifyState());
        }
        Integer singInMethod = recordRepository.getPointSingInMethodByPlanId(recordVO.getCheckPlanId());
        if (singInMethod != null) {
            record.setVerifyType(singInMethod.toString());
        }
        //异常提醒
        Optional<BpInvestigatePlan> optionalPlan = planRepository.findById(recordVO.getCheckPlanId());
        BpInvestigatePlan plan = optionalPlan.get();
        //签到异常需要向报警中心添加报警信息(record.getCheckUserId(),时间,状态)
        if ("签到异常".equals(recordVO.getVerifyState())) {
            try {
                if (plan != null) {
                    inspectExceptionAlarmMesageService.saveMessage(recordVO.getCheckPlanId(), record.getCheckUserId(), AlarmContentTypes.INVESTIGATE_SIGN_IN_EXCEPTION.getCode(), Context.getCurrentTenantId(), Context.getCurrentOrgCode());
                }
            } catch (Exception e) {
                log.error("巡检报警推送错误:{}", e);
            }
        }
        record = recordRepository.save(record);
        Long itemId = saveRecordItem(itemVO, record.getId(), checkResult);
   //     Long evalItemId = bpInvestigateRecordItemDao.getPointEvalItemIdById(itemId);
        //任务处理
        if (taskId != null) {
            Optional<BpInvestigateTask> optionalTask = taskDao.findById(taskId);
            if (optionalTask.isPresent()) {
                BpInvestigateTask task = optionalTask.get();
                task.setStatus(InvestigateTaskStatus.DONE.getStatus());
                task.setFinishDate(new Date());
                task.setRecordId(record.getId());
                taskDao.save(task);
                try {
                    // 删除其他人task_assign数据
                    List<Long> taskIds = Collections.singletonList(task.getId());
                    if (!CollectionUtils.isEmpty(taskIds)) {
                        bpInvestigateTaskAssignService.deleteByTaskIdsAndUserIdNe(taskIds, Context.getCurrentUserId());
                    }
                } catch (Exception e) {
                    log.error("删除隐患排查任务异常: taskId: {}, {}", taskId, e.getMessage());
                }
                if (null == recordVO.getId()) {
                    // 仅第一次提交更新汇总
                    SummaryToUpDateBean summaryWillUpdate = new SummaryToUpDateBean(record.getCheckFinishDate(), itemVO.getAction(), Context.getCurrentUserId());
                    redisClient.hput(Constant.INVESTIGATION_SUMMARY_UPDATE_KEY, task.getId().toString(), JSON.toJSONString(summaryWillUpdate));
                }

                if (plan != null) {
                    exceptionNotify(record, plan);
                    // 检查结果为异常(仅第一次提交)，风险管控计划失效
                    if (recordVO.getRecordItem().getId() == null && RecordActionType.EX.getValue().equals(record.getCheckResult())) {
                        plan.setInvalidFlag(Constant.COMMON_SWITCH_ON);
                        plan.setInvalidReason(record.getCheckResult());
                        planRepository.save(plan);
//                        // 通知风险评估模块管控失效，重新计算风险等级
//                        if (evalItemId != null) {
//                            evaluationBusinessService.recalculateRealRiskLevel(ControlRiskLevelType.INVALID.getValue(), new RiskItemEvalCountRecordVo("无效", "saveV2", evalItemId));
//                        }
                        //检查异常向报警中心添加巡检异常信息
                        try {
                            inspectExceptionAlarmMesageService.saveMessage(recordVO.getCheckPlanId(), record.getCheckUserId(), AlarmContentTypes.INVESTIGATE_FIND_EXCEPTION.getCode(), Context.getCurrentTenantId(), Context.getCurrentOrgCode());
                        } catch (Exception e) {
                            log.error("巡检报警推送错误:{}", e);
                        }
                    }
                    if (recordVO.getRecordItem().getId() == null
                            && (RecordActionType.EX.getValue().equals(record.getCheckResult()) || VerifyState.ABNORMAL.getState().equals(recordVO.getVerifyState()))) {
                        Integer notifyType = null;
                        if (!RecordActionType.EX.getValue().equals(record.getCheckResult())) {
                            // 只签到异常
                            notifyType = 1;
                        } else if (!VerifyState.ABNORMAL.getState().equals(recordVO.getVerifyState())) {
                            // 只上报异常
                            notifyType = 0;
                        } else {
                            // 两者都异常
                            notifyType = 2;
                        }
                        try {
                            generateAppNotifyForNew(task, recordVO.getCheckPlanId(), notifyType);
                        } catch (Exception e) {
                            log.error("generate app notify error:{}", e);
                        }
                    }
                }
            }
        }
        //未检恢复
//        Map<Long, List<Long>> itemPlanMap = new HashMap<>();
//        if (evalItemId != null && recordVO.getCheckPlanId() != null) {
//            RiskEvaluationControl control = riskEvaluationTempleService.getRiskEvControlFromRedis();
//            if (control != null && Constant.COMMON_SWITCH_ON.equals(control.getSwitchState().toString())) {
//                itemPlanMap.put(evalItemId, Lists.newArrayList(recordVO.getCheckPlanId()));
//                evaluationBusinessService.convertCheckedRealRiskLevel(itemPlanMap, "saveV2");
//            }
//        }
        // 取消即将逾期通知
        commonBusinessNoticeService.deleteByRefIdAndTitle(taskId);
        return itemId;
    }


    /**
     * app消息中心\个推-新任务上报异常、签到异常
     * type： 0上报异常，1位置异常，2两者都异常
     */
    private void generateAppNotifyForNew(BpInvestigateTask task, Long planId, Integer type) {
        Long taskId = task.getId();
        CommonBusinessNotice commonBusinessNotice = new CommonBusinessNotice();
        StringBuilder msg = new StringBuilder();
        Long pointId = inspectExceptionAlarmMesageMapper.getRiskPointByplanId(planId);
        RiskPoint riskPoint = riskPointService.findByIdIgnoreDeleteStatus(pointId);
        String pointName = riskPoint.getName();
        ShiroUser currentUser = Context.getCurrentUser();
        String realName = currentUser.getRealName();
        SimpleDateFormat sdf = null;
        if (CycleType.H.getValue().equals(task.getPeriodUnit())) {
            sdf = SimpleDateFormatCache.getYmdh();
        } else {
            sdf = SimpleDateFormatCache.getYmd();
        }
        String taskTime = sdf.format(task.getCheckDate());
        msg.append(Constant.COLON_ENGLISH)
                .append(pointName)
                .append(Constant.COLON_ENGLISH)
                .append(realName)
                .append(taskTime)
                .append(AppNotifyContentSuf.TASK_ABNORMAL);
        if (type == 0) {
            // 排查上报异常文案
            msg.append(AppNotifyContentSuf.TASK_FIND_ABNORMAL);
        } else if (type == 1) {
            // 排查签到异常文案
            msg.append(AppNotifyContentSuf.TASK_VERIFY_ABNORMAL);
        } else {
            msg.append(AppNotifyContentSuf.TASK_BOTH_ABNORMAL);
        }
        BpDepart depart = bpDepartDao.findById(currentUser.getDepartId()).get();
        if (depart != null && depart.getChiefId() != null) {
            //加入开关
            boolean exceptionCheck = false;
            String exceptionStatus = investigateConfigService.getStatusByName(InvestigateConfigNames.TROUBLESHOOTING_EXCEPTION_NOTIFICATION);
            exceptionCheck = org.apache.commons.lang3.StringUtils.isNotBlank(exceptionStatus) && Constant.COMMON_SWITCH_ON.equals(exceptionStatus);
            if (exceptionCheck) {
                commonBusinessNotice.setNoticeContent(msg.toString())
                        .setNoticeTitle(AppNotifyContentPre.TASK_EX_NOTIFY)
                        .setBusinessType(AppBusinessNoticeTypes.INVESTIGATE.getType())
                        .setNoticeUser(depart.getChiefId())
                        .setSendTime(new Date())
                        .setRefId(taskId);
                commonBusinessNoticeService.save(commonBusinessNotice);
            }
            boolean needPush = false;
            BaseConfig config = baseConfigService.findFirstConfig(BaseConfigCodes.INVESTIGATE_GETUI_ON_OFF);
            needPush = null != config && Constant.COMMON_SWITCH_ON.equals(config.getValue());
            // 个推
            if (needPush && exceptionCheck) {
                noticeWaitingTriggerListService.save(new HashSet<Long>(Lists.newArrayList(depart.getChiefId())),
                        commonBusinessNotice.getBusinessType(),
                        commonBusinessNotice.getNoticeContent(),
                        BusinessTypeEnum.INVESTIGATE_GEN_TASK.getBusinessCode(),
                        taskId.toString(), new Date());
            }
        }
    }

    /**
     * app消息中心\个推-老任务上报异常
     */
    void generateAppNotifyForOld(BpInvestigateTask task, Long planId, Long userId) {
        Long taskId = task.getId();
        BpInvestigatePlan plan = planRepository.findFirstById(planId);
        StringBuilder msg = new StringBuilder();
        BaseUser user = baseUserDao.findById(userId).get();
        String realName = baseUserDao.getRealNameById(userId);
        msg.append(Constant.COLON_ENGLISH)
                .append(plan.getCheckPlanName())
                .append(Constant.COLON_ENGLISH)
                .append(realName)
                .append(SimpleDateFormatCache.getYmd().format(task.getCheckDate()))
                .append(AppNotifyContentSuf.TASK_ABNORMAL);
        BpDepart depart = bpDepartDao.findById(user.getDepartId()).get();
        if (depart != null && depart.getChiefId() != null) {
            //排查异常通知开关
            boolean exceptionCheck = false;
            String exceptionStatus = investigateConfigService.getStatusByName(InvestigateConfigNames.TROUBLESHOOTING_EXCEPTION_NOTIFICATION);
            exceptionCheck = org.apache.commons.lang3.StringUtils.isNotBlank(exceptionStatus) && Constant.COMMON_SWITCH_ON.equals(exceptionStatus);
            CommonBusinessNotice commonBusinessNotice = new CommonBusinessNotice();
            if (exceptionCheck) {
                commonBusinessNotice.setNoticeContent(msg.toString())
                        .setNoticeTitle(AppNotifyContentPre.TASK_EX_NOTIFY)
                        .setBusinessType(AppBusinessNoticeTypes.INVESTIGATE.getType())
                        .setNoticeUser(depart.getChiefId())
                        .setSendTime(new Date())
                        .setRefId(taskId);
                // app消息中心
                commonBusinessNoticeService.save(commonBusinessNotice);
            }
            // 个推,可配置开关
            boolean needPush = false;
            BaseConfig config = baseConfigService.findFirstConfig(BaseConfigCodes.INVESTIGATE_GETUI_ON_OFF);
            needPush = null != config && Constant.COMMON_SWITCH_ON.equals(config.getValue());
            if (needPush && exceptionCheck) {
                noticeWaitingTriggerListService.save(new HashSet<Long>(Lists.newArrayList(depart.getChiefId())),
                        commonBusinessNotice.getBusinessType(),
                        commonBusinessNotice.getNoticeContent(),
                        BusinessTypeEnum.INVESTIGATE_TASK_EX.getBusinessCode(),
                        taskId.toString(), new Date());
            }
        }

    }

    @Override
    public PositionCheckBean positionCheck(Long userId, Long pointId, Long taskId) throws Exception {
        // K：prefix:companyCode:userId  V：{pointId:xxx,location:{x:xx.xx,y:xx.xx,z:xx.xx,floorId:xx}}
        String redisKey = Constant.INVESTIGATION_POSITION_CHECK_PREFIX + Constant.SPLIT_COLON + Context.getCurrentTenantId() + Constant.SPLIT_COLON + Context.getCompanyCode() + Constant.SPLIT_COLON + userId;
        PositionCheckBO pointCheckCache = JSON.parseObject(redisClient.get(redisKey), PositionCheckBO.class);
        // HashMap<String, String> redisValue = new HashMap<>();
        if (pointCheckCache != null && pointId.equals(pointCheckCache.getPointId())) {
            // 十分钟内在本风险点签过到，不进行校验，直接返回十分钟前的位置
            return new PositionCheckBean(true, pointCheckCache.getLocation());
        }
        BaseUser user = baseUserDao.findById(userId).get();
        String sn = user.getSn();
        // 定位卡号不为空
        if (StringUtils.isEmpty(sn)) {
            saveVerifyLog(userId, taskId, null, LocationVerifyStateEnum.SN_NOT_EXIST.getValue());
            throw new IllegalArgumentException(Status.USER_SN_IS_NULL.getMsg());
        }
        TrajectoryLastLocationResp userLocation = null;
        try {
            userLocation = personTrajectory.getLastLocation(sn, null, IdUtil.simpleUUID());
        } catch (ApiCoreException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
        // 未获取到人员位置
        if (userLocation == null) {
            saveVerifyLog(userId, taskId, null, LocationVerifyStateEnum.NO_LAST_POINT.getValue());
            return new PositionCheckBean(false, null);
        }
        // 用户位置处理
        Double longitude = userLocation.getLongitude();
        Double latitude = userLocation.getLatitude();
        String floorNo = userLocation.getFloorNo();
        // 开放平台楼层转换
        Long floorId = Long.parseLong(floorNo.replace(Constant.FLOOR_REPLACE_STR, Constant.EMPTY_STR));
        FencePoint selfLocation = new FencePoint(longitude, latitude, 0, floorId);
        String locationJsonStr = JsonUtil.toJson(selfLocation);
        // 最后点位在十分钟之外，等同于未获取到位置，直接返回校验失败，位置信息不予返回
        if (System.currentTimeMillis() - userLocation.getTimestampMillisecond() > 1000 * 60 * 10) {
            saveVerifyLog(userId, taskId, locationJsonStr, LocationVerifyStateEnum.LAST_POINT_NOT_IN_MAX_TIME_RANGE.getValue());
            return new PositionCheckBean(false, null);
        }
        // 风险点位置处理
        RiskPoint point = riskPointDao.getById(pointId);
        String pointLocationStr = point.getPoints();
        boolean needCheckFloor = Integer.valueOf(1).equals(point.getDistinguishFloor());
        // 风险点未画围栏
        Assert.isTrue(!StringUtils.isEmpty(pointLocationStr), Status.POINT_NONE_POSITION.getMsg());
        List<FencePoint> pointLocation = JsonUtil.fromListJson(pointLocationStr, FencePoint.class);
        Long pointFloorId = point.getFloorId();
        // 区分楼层
        if (needCheckFloor && !floorId.equals(pointFloorId)) {
            saveVerifyLog(userId, taskId, locationJsonStr, LocationVerifyStateEnum.INCONSISTENT_FLOOR.getValue());
            return new PositionCheckBean(false, locationJsonStr);
        }
        Double[] lonArr = new Double[pointLocation.size()];
        Double[] latArr = new Double[pointLocation.size()];
        getCoordinateArr(pointLocation, lonArr, latArr);
        boolean verifySuccess = RegionUtil.isInPolygon(longitude, latitude, lonArr, latArr);
        // 位置校验成功后缓存10分钟
        if (verifySuccess) {
            PositionCheckBO positionCheckBO = new PositionCheckBO(pointId, locationJsonStr);
            String redisValue = JSON.toJSONString(positionCheckBO);
            BaseConfig cacheTimeFig = baseConfigService.findFirstConfig(BaseConfigCodes.POSITION_CHECK_CACHE_TIME);
            Long cacheTime = null;
            try {
                cacheTime = Long.valueOf(cacheTimeFig.getValue());
            } catch (Exception e) {
                throw new Exception(Status.POSITION_CHECK_CACHE_TIME_ERROR.getMsg());
            }
            redisClient.setEx(redisKey, redisValue, cacheTime, TimeUnit.MINUTES);
        }
        saveVerifyLog(userId, taskId, locationJsonStr, verifySuccess ? LocationVerifyStateEnum.POINT_IN_AREA.getValue() : LocationVerifyStateEnum.POINT_OUT_AREA.getValue());
        return new PositionCheckBean(verifySuccess, locationJsonStr);
    }

    /**
     * 点位转换经纬度数组
     *
     * @param points
     * @param lonArr
     * @param latArr
     */
    private void getCoordinateArr(List<FencePoint> points, Double[] lonArr, Double[] latArr) {
        int i = 0;
        for (FencePoint each : points) {
            lonArr[i] = each.getX();
            latArr[i] = each.getY();
            i++;
        }
    }

    /**
     * 保存位置校验记录
     */
    private void saveVerifyLog(Long userId, Long taskId, String location, Integer verifyState) {
        try {
            BpInvestigateVerifyLog verifyLog = BpInvestigateVerifyLog.builder()
                    .userId(userId)
                    .taskId(taskId)
                    .location(location)
                    .verifyState(verifyState)
                    .verifyTime(new Date())
                    .build();
            verifyLogService.saveVerifyLog(verifyLog);
        } catch (Exception e) {
            log.error("Save verify Log error.", e);
        }
    }

    @Override
    public void updateSummaryTask(final Date taskCheckDate, final Long taskId, final String action, final Long userId) {
        // 该任务分配到的人
        LambdaQueryWrapper<BpInvestigateTaskAssign> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BpInvestigateTaskAssign::getTaskId, taskId);
        wrapper.eq(BpInvestigateTaskAssign::getDeleteFlag, DeleteFlag.EFFECTIVE.getCode());
        List<BpInvestigateTaskAssign> assignList = bpInvestigateTaskAssignService.list(wrapper);

        List<BpInvestigateTaskSummary> taskSummaryList = new ArrayList<>();
        Date startTime = DateUtil.beginOfDay(taskCheckDate);
        DateTime endTime = DateUtil.beginOfDay(DateUtil.offsetDay(taskCheckDate, 1));
        // 更新该任务生成时的汇总状态及各类count数
        updateSummarysStatusAndCount(taskId, action, userId);
        if (!CollectionUtils.isEmpty(assignList)){
            //准备数据
            List<Long> assignUserIds = assignList.stream().map(BpInvestigateTaskAssign::getAssignUser).collect(Collectors.toList());
            List<BpInvestigateTaskSummary> summaryList = summaryMapper.getByDateAndUserIds(startTime, endTime,assignUserIds);
            Map<Long, BpInvestigateTaskSummary> summaryMap = summaryList.stream().collect(Collectors.toMap(BpInvestigateTaskSummary::getUserId, e -> e));
            List<UserTaskRecordDto> userTaskRecordDtoList = summaryMapper.findTaskByDateAndUserIdsOrderByFinishDate(startTime, endTime, assignUserIds);
            Map<Long, List<UserTaskRecordDto>> userTaskRecordMap = userTaskRecordDtoList.stream().collect(Collectors.groupingBy(UserTaskRecordDto::getAssignUser));

            // 更新该任务完成时的汇总各类状态
            assignList.forEach(assign -> {
//                BpInvestigateTaskSummary summary = summaryMapper.getByDateAndUserId(startTime, endTime, assign.getAssignUser());
                BpInvestigateTaskSummary summary = summaryMap.get(assign.getAssignUser());
                if (summary == null){
                    return;
                }
//                List<UserTaskRecordDto> userTaskRecords = summaryMapper.findTaskByDateOrderByFinishDate(startTime, endTime, assign.getAssignUser());
                List<UserTaskRecordDto> userTaskRecords = userTaskRecordMap.get(assign.getAssignUser());
                List<String> checkResultList = new ArrayList<>();
                List<Long> checkPlanIds = new ArrayList<>();
                if (!CollectionUtils.isEmpty(userTaskRecords)) {
                    List<String> exceptionProcessList = userTaskRecords.stream().map(UserTaskRecordDto::getRepairStatus).filter(ex -> org.apache.commons.lang3.StringUtils.isNotBlank(ex) && !RepairStatus.NO_RECTIFICATION_REQUIRED.getDesc().equals(ex)).collect(Collectors.toList());
                    // 只有异常的时候会影响到异常处理状态
                    String exceptionHandleStatus = calculateExceptionHandleStatus(action, exceptionProcessList);
                    if (StringUtils.isNotBlank(exceptionHandleStatus)) {
                        summary.setExceptionProcessResult(exceptionHandleStatus);
                    }
                    UserTaskRecordDto lastTask = null;
                    for (UserTaskRecordDto record : userTaskRecords) {
                        if (!RecordActionType.UC.getValue().equals(record.getCheckResult())) {
                            lastTask = record;
                            break;
                        }
                    }
                    if (lastTask != null) {
                        summary.setCheckCompleteDate(lastTask.getCheckFinishDate());
                        summary.setCheckCompleteUserId(lastTask.getCheckUserId());
                    }
                    // 检查结果：正常、异常、未检
                    checkResultList = userTaskRecords.stream().map(UserTaskRecordDto::getCheckResult).filter(org.apache.commons.lang3.StringUtils::isNotBlank).collect(Collectors.toList());
                    checkPlanIds = userTaskRecords.stream().map(UserTaskRecordDto::getCheckPlanId).collect(Collectors.toList());
                }
                /*
                 * 注意：
                 * 此检查结果不可使用summary上的count数计算得出。
                 * count数记录的是任务生成时间在汇总当天的所有任务
                 * 而此检查结果受所有汇总所在当天实际完成的任务影响
                 */
                String checkResult = calculateCheckResult(checkResultList,checkPlanIds);
                summary.setCheckResult(checkResult);
                summary.setHasProcessRecord(Boolean.TRUE);
                taskSummaryList.add(summary);
            });
        }
        if (!CollectionUtils.isEmpty(taskSummaryList)) {
            bpInvestigateTaskSummaryService.updateBatchById(taskSummaryList);
        }
    }


    /**
     * 更新任务状态和各类count
     *
     * @param taskId
     * @param action
     * @param userId
     */
    private void updateSummarysStatusAndCount(Long taskId, String action, Long userId) {
        /*
         * 注意区分三种汇总与任务的关联：
         * 1、按任务开始时间。即是任务开始时间落在汇总所在天的00:00-23:59
         * 2、按任务实际完成时间。即是任务实际完成时间落在汇总所在天的00:00-23:59
         * 3、按任务的开始和截止时间，只要当天可做，就算相关。即是任务开始时间大于汇总所在天的23:59且任务结束时间小于汇总当天的00:00
         * updateSummarysStatusAndCount与updateSummaryTask分开写的原因：
         *
         * updateSummaryTask中需要更新状态的summary为 任务实际完成时间，所在当天的汇总。（关联关系为第2种）
         * updateSummarysStatusAndCount中需要更新状态的summary为 任务开始时间，所在当天的汇总。（关联关系为第1种）
         *
         * 另，关联关系为第一种时，直接用assign中的summaryId字段关联即可
         */
        BpInvestigateTask task = taskDao.findById(taskId).orElse(null);
        boolean isHistory = false;
        if (task != null) {
            /**
             * 如果任务开始时间不是今天，则说明是跨天任务，
             * 需要更新完成状态和统计数据的汇总大概率在history表中
             * 大概率 原因：每天01:30挪数据，在这1.5个小时中，历史汇总仍存在于今日表中
             */
            List<BpInvestigateTaskSummary> summaryList = null;
            if (task.getCheckDate().before(DateUtil.beginOfDay(new Date()))) {
                // 开始时间早于今日，先查历史表，历史表没有再查今日表
                isHistory = true;
                summaryList = summaryMapper.getByHistoryTaskId(taskId);
                if (CollectionUtil.isEmpty(summaryList)) {
                    isHistory = false;
                    summaryList = summaryMapper.getByTodayTaskId(taskId);
                }
                //summaryList为空的时候先查询当天的任务汇总
                if (CollectionUtils.isEmpty(summaryList)) {
                    summaryList = summaryMapper.selectSummaryList(taskId);
                    if (CollectionUtils.isEmpty(summaryList)) {
                        isHistory = true;
                        summaryList = summaryMapper.getByHisTakId(taskId);
                    }
                }
            }else {
                // 开始时间在今日，直接查今日表。
                summaryList = summaryMapper.getByTodayTaskId(taskId);
            }

            if (CollectionUtil.isNotEmpty(summaryList)) {
                for (BpInvestigateTaskSummary summary : summaryList) {
                    // 未检：不区分人工操作或者非人工操作  任务完成数+1
                    if (RecordActionType.UC.getValue().equals(action)) {
                        summary.setUncheckCount(summary.getUncheckCount() + 1);
                    }else if (RecordActionType.EX.getValue().equals(action)) {
                        // 异常
                        if (userId == null || userId.equals(summary.getUserId())) {
                            // 非人工操作 或者 人工操作且是完成人  任务完成数+1、异常数+1
                            summary.setTaskDoneCount(summary.getTaskDoneCount() + 1);
                            summary.setExceptionCount(summary.getExceptionCount() + 1);
                        } else {
                            // 人工操作且是非完成人  任务数 -1
                            summary.setTaskCount(Math.max(summary.getTaskCount() - 1, 0));
                        }
                    } else if (RecordActionType.NM.getValue().equals(action)) {
                        // 正常
                        if (userId == null || userId.equals(summary.getUserId())) {
                            // 非人工操作 或者 人工操作且是完成人  任务完成数 +1
                            summary.setTaskDoneCount(summary.getTaskDoneCount() + 1);
                        } else {
                            // 人工操作且是非完成人  任务数 -1
                            summary.setTaskCount(Math.max(summary.getTaskCount() - 1, 0));
                        }
                    }
                    summary.setCheckStatus(summary.getUncheckCount() + summary.getTaskDoneCount() >= summary.getTaskCount() ?
                            InvestigateTaskStatus.DONE.getStatus():InvestigateTaskStatus.NO.getStatus());
                }
                if (isHistory) {
                    summaryHisService.updateBatchById(convertSummaryToHistory(summaryList));
                }else {
                    bpInvestigateTaskSummaryService.updateBatchById(summaryList);
                }
            }
        }
    }

    private String calculateCheckResult(List<String> checkResultList,List<Long> checkPlanIds) {
        if (!CollectionUtils.isEmpty(checkPlanIds)){
            List<BpInvestigatePlan> plans = planRepository.findAllById(checkPlanIds);
            if (CollectionUtils.isEmpty(plans)){
                return RecordActionType.NM.getValue();
            }
        }
        if (CollectionUtil.isNotEmpty(checkResultList)) {
            if (checkResultList.contains(RecordActionType.EX.getValue())) {
                // 存在异常 -> 异常
                return RecordActionType.EX.getValue();
            }else if(checkResultList.contains(RecordActionType.UC.getValue())) {
                // 不存在异常、存在未检 -> 未检
                return RecordActionType.UC.getValue();
            }else {
                // 不存在异常、不存在未检 -> 正常
                return RecordActionType.NM.getValue();
            }
        }
        return null;
    }

    private List<BpInvestigateTaskSummaryHis> convertSummaryToHistory(List<BpInvestigateTaskSummary> list) {
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        ArrayList<BpInvestigateTaskSummaryHis> result = new ArrayList<>();
        list.forEach(each -> {
            BpInvestigateTaskSummaryHis summaryHis = new BpInvestigateTaskSummaryHis();
            BeanUtils.copyProperties(each, summaryHis);
            result.add(summaryHis);
        });
        return result;
    }

    @Deprecated
    private void calculateCheckResultV2(BpInvestigateTaskSummary summary) {
        int exceptionCount = summary.getExceptionCount();
        int uncheckCount = summary.getUncheckCount();

        if (exceptionCount > 0) {
            // 存在异常 -> 异常
            summary.setCheckResult(RecordActionType.EX.getValue());
        }else if (uncheckCount > 0) {
            // 不存在异常、存在未检 -> 未检
            summary.setCheckResult(RecordActionType.UC.getValue());
        }else {
            summary.setCheckResult(RecordActionType.NM.getValue());
        }
    }


    @Override
    public String calculateExceptionHandleStatus(String checkResult, List<String> exceptionProcessList) {
        String exceptionHandleStatus = null;
        RecordActionType action = RecordActionType.find(checkResult);
        switch (action) {
            case EX:
                if (exceptionProcessList.contains(RepairStatus.NOT_RECTIFIED.getDesc())) {
                    exceptionHandleStatus = RepairStatus.WAITING_FOR_PROCESSING.getDesc();
                } else {
                    exceptionHandleStatus = RepairStatus.PROCESSED.getDesc();
                }
                break;
            case UC:
            case NM:
                if (exceptionProcessList.contains(RepairStatus.NOT_RECTIFIED.getDesc())) {
                    exceptionHandleStatus = RepairStatus.WAITING_FOR_PROCESSING.getDesc();
                } else {
                    exceptionHandleStatus = RepairStatus.NO_PROCESSING_REQUIRED.getDesc();
                }
                break;
            default:
                break;
        }
        return exceptionHandleStatus;
    }

    private Long saveRecordItem(BpInvestigateRecordItemVO itemVO, Long recordId, String checkResult) {
        BpInvestigateRecordItem recordItem = recordItemDao.findFirstByRecordId(recordId);
        if (recordItem == null) {
            recordItem = itemVO.getId() == null ? new BpInvestigateRecordItem().setId(YitIdHelper.nextId()) : recordItemDao.findById(itemVO.getId()).orElse(new BpInvestigateRecordItem().setId(YitIdHelper.nextId()));
        }
        if (StringUtils.isEmpty(recordItem.getRepairStatus())) {
            if (RecordActionType.EX.getValue().equals(itemVO.getAction())) {
                recordItem.setRepairStatus("未整改");
            } else {
                recordItem.setRepairStatus("无需整改");
            }
        }
        List<BaseAttachmentBean> attachmentList = itemVO.getAttachmentList();
        recordItem.setAttachmentJson(attachmentList == null ? null : JSON.toJSONString(attachmentList));
        recordItem.setRecordId(recordId);
        recordItem.setProblemDescription(itemVO.getProblemDescription());
        recordItem.setAction(checkResult);
        recordItemDao.save(recordItem);
        return recordItem.getId();
    }

    @Override
    public void exceptionNotify(BpInvestigateRecord record, BpInvestigatePlan plan) {
        String checkResult = record.getCheckResult();
        if (!(checkResult.contains("异常"))) {
            return;
        }
        String planName = plan.getCheckPlanName();
        String remindUserJson = plan.getRemindUserJson();
        if (StringUtils.isEmpty(remindUserJson)) {
            return;
        }
        List<Long> userIdList = JSON.parseArray(remindUserJson, Long.class);
        List<CommonIndexNotify> needSaveList = Lists.newArrayList();
        for (Long userId : userIdList) {
            CommonIndexNotify notify = new CommonIndexNotify();
            notify.setType(CommonIndexNotifyTypes.INVESTIGATE_TASK.getType());
            notify.setEduCertUserId(record.getId());
            LocalDate now = LocalDate.now();
            notify.setRemindDate(now);
            notify.setRemindDateTime(LocalDateTime.of(now, LocalTime.of(0, 0, 0)));
            notify.setUserId(userId);
            //提醒message格式：“隐患排查计划名称”发生“异常类型”。
            String message = planName + "发生" + checkResult;
            notify.setNotifyMessage(message);
            needSaveList.add(notify);
        }
        if (!CollectionUtils.isEmpty(needSaveList)) {
            commonIndexNotifyDao.saveAll(needSaveList);
        }
    }

    @Override
    public List<Long> saveV3(List<BpInvestigateRecordVO> recordVOList) {
        List<Long> idList = Lists.newArrayList();
        if (recordVOList != null) {
            recordVOList.forEach(vo -> {
                Long id = saveV2(vo);
                if (id != null) {
                    idList.add(id);
                }
            });
        }

        return idList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long repairNewWf(Long itemId, String wfProcessInsId, String wfProcessStatus) {
        BpInvestigateRecordItem recordItem = recordItemDao.findById(itemId).orElse(null);
        if (null != recordItem) {
            recordItem.setRepairStatus("已处理");
            recordItem.setWfProcessInsId(wfProcessInsId);
            recordItem.setWfProcessStatus(wfProcessStatus);
            recordItemDao.save(recordItem);
        } else {
            recordItem = investigateHistoryMapper.getHistoryItemById(itemId);
            investigateHistoryMapper.updateRecordItemRepairStatusAndWfStatus(itemId,"已处理",
                    wfProcessInsId, wfProcessStatus);
        }
        // 更新summary的异常处理状态
        bpInvestigateTaskSummaryService.updateSummaryRepairStatusV2(itemId);
        return null != recordItem ? recordItem.getId() : null;
    }

    @Override
    public List<BpInvestigateRecordItemDto> findWfRecordItemList() {
        return recordItemMapper.findWfRecordItemList();
    }

    @Override
    public boolean updateWfRecordItemByIds(String status, List<Long> ids) {
        if (StringUtils.isNotBlank(status) && ObjectUtil.isNotEmpty(ids)) {
            return recordItemMapper.updateWfRecordItemByIds(status, ids);
        } else {
            log.warn("updateWfRecordItemByIds error. ids[{}],status:{}", JSONUtil.toJsonStr(ids), status);
        }
        return false;
    }

    @Override
    public boolean updateWfRecordItemHisByIds(String status, List<Long> ids) {
        if (StringUtils.isNotBlank(status) && ObjectUtil.isNotEmpty(ids)) {
            return recordItemMapper.updateWfRecordItemHisByIds(status, ids);
        } else {
            log.warn("updateWfRecordItemByIds error. ids[{}],status:{}", JSONUtil.toJsonStr(ids), status);
        }
        return false;
    }

    private void setRecordResult(BpInvestigateRecord record, String result) {
        String checkResult = record.getCheckResult();
        if (checkResult == null) {
            record.setCheckResult(result);
        } else {
            if (checkResult.contains(result)) {
                return;
            }
            record.setCheckResult(checkResult + "," + result);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultBean deleteByIds(List<Long> ids) {
        recordItemDao.deleteByRecordIds(ids);
        recordRepository.deleteByIds(ids);
        return ResultBean.defaultSuccessResult();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultBean delete(Long id) {
        boolean isHistory = false;
        BpInvestigateRecord record = recordRepository.findById(id).orElse(null);
        if (null == record) {
            isHistory = true;
            record = investigateHistoryMapper.getRecordById(id);
        }
        if (isHistory) {
            investigateHistoryMapper.deleteRecordHistoryById(id);
            investigateHistoryMapper.deleteRecordItemHistoryByRecordId(id);
        }else {
            recordItemDao.deleteByRecordId(id);
            recordRepository.deleteById(id);
        }
        // 重置相关的计数
        investigateHistoryMapper.resetSummaryCountByTaskId(record.getTaskId(), isHistory);
        return ResultBean.defaultSuccessResult();
    }

    //flag: 0 web; 1 app(需要根据项目名称做组合)
    @Override
    public ResultBean getById(Long id, Integer flag) {
        // 兼容历史页面和今日页面
        BpInvestigateRecord record = recordRepository.findById(id).orElse(investigateHistoryMapper.getRecordById(id));
        if (null == record) {
            throw new IllegalArgumentException("此数据不存在或已被删除");
        }

        BpInvestigateRecordBean recordBean = new BpInvestigateRecordBean();
        BeanUtils.copyProperties(record, recordBean);
        //计划相关
        BpInvestigatePlanBean planBean = (BpInvestigatePlanBean) planService.getById(record.getCheckPlanId(), flag).getData();
        recordBean.setPlanBean(planBean);
        recordBean.setCheckUserName(baseUserDao.getRealNameById(record.getCheckUserId()));
        recordBean.setDutyDepartName(bpDepartDao.getNameById(recordBean.getDutyDepartId()));
        //参与人员
        if (org.apache.commons.lang3.StringUtils.isNotBlank(record.getParticipants())) {
            recordBean.setParticipants(JSONArray.parseArray(record.getParticipants(), BpBaseUserBean.class));
        }
        //检查项目
        List<BpInvestigateRecordItem> itemList = recordItemDao.findByRecordId(record.getId());
        if (CollectionUtil.isEmpty(itemList)) {
            itemList = investigateHistoryMapper.getHistoryItemByRecordId(record.getId());
        }
        String autograph="";
        BaseConfig config = baseConfigService.findFirstConfig(BaseConfigCodes.AUTOGRAPH);
        if (config != null && config.getValue().equals("开启")&&recordBean.getCheckUserId()!=null) {
            autograph= baseUserDao.getAutograph(recordBean.getCheckUserId());
        }
        List<Long> itemIdList = itemList.stream().map(r -> r.getCheckItemId()).distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(itemList)) {
            Map<Long, BpSafeTableItem> tableItemMap = tableItemDao.findAllById(itemIdList).stream().collect(Collectors.toMap(r -> r.getId(), r -> r));
            List<BpInvestigateRecordItemBean> itemBeanList = getBpInvestigateRecordItemBeans(itemList, tableItemMap,autograph);
            if (flag == 0) {
                recordBean.setItemBeanList(itemBeanList);
            } else {
                Map<Long, List<BpInvestigateRecordItemBean>> itemMap = itemBeanList.stream().collect(Collectors.groupingBy(r -> r.getCheckItemId()));
                List<AppInvestigateRecordDto> resultList = Lists.newArrayList();
                Long exceptionSum = 0L;
                for (Long itemId : itemMap.keySet()) {
                    List<BpInvestigateRecordItemBean> itemBeans = itemMap.get(itemId);
                    exceptionSum += itemBeans.stream().filter(r -> "异常".equals(r.getAction())).count();
                    BpSafeTableItem item = tableItemMap.get(itemId);
                    resultList.add(new AppInvestigateRecordDto(item != null ? item.getItem() : "", itemBeans.size(), itemBeans));
                }
                recordBean.setExceptionSum(exceptionSum.intValue());
                recordBean.setRecordDtoList(resultList);
            }
        }
        return ResultBean.success(recordBean);
    }

    private List<BpInvestigateRecordItemBean> getBpInvestigateRecordItemBeans
            (List<BpInvestigateRecordItem> itemList, Map<Long, BpSafeTableItem> tableItemMap,String autograph) {
        List<BpInvestigateRecordItemBean> itemBeanList = Lists.newArrayList();
        for (BpInvestigateRecordItem recordItem : itemList) {
            BpInvestigateRecordItemBean itemBean = new BpInvestigateRecordItemBean();
            BeanUtils.copyProperties(recordItem, itemBean);
            BpSafeTableItem tableItem = tableItemMap.get(itemBean.getCheckItemId());
            if (tableItem != null) {
                itemBean.setItem(tableItem.getItem());
                itemBean.setContent(tableItem.getContent());
                itemBean.setStandard(tableItem.getStandard());
            }
            String json = recordItem.getAttachmentJson();
            if (!StringUtils.isEmpty(json)) {
                //兼容APP保存的图片，去除空的图片
                List<BaseAttachmentBean> baseAttachmentBeans = JSON.parseArray(json, BaseAttachmentBean.class).stream().filter(e -> e.getId() != null).collect(Collectors.toList());
                itemBean.setAttachmentList(baseAttachmentBeans);
            }
            itemBeanList.add(itemBean);
            //流程任务数据填充
            Long workFlowTaskId = recordItem.getWorkFlowTaskId();
            if (workFlowTaskId != null) {
                itemBean.setWorkFlowTaskId(workFlowTaskId);
                workFlowTaskDao.findById(workFlowTaskId).ifPresent(r -> {
                    itemBean.setWorkFlowProcessId(r.getProcessId());
                    itemBean.setWorkFlowFormData(r.getFormData());
                    itemBean.setWorkFlowTaskId(workFlowTaskId);
                    itemBean.setWorkFlowStatus(r.getState());
                });
            }
            String wfProcessInsId = recordItem.getWfProcessInsId();
            if (StringUtils.isNotBlank(wfProcessInsId)) {
                itemBean.setWorkFlowStatus(recordItem.getWfProcessStatus());
            }
            itemBean.setAutograph(autograph);
        }
        return itemBeanList;
    }

    //flag: 0 web; 1 app(当前用户生成的记录)
    @Override
    public ResultBean page(BpInvestigateRecordQueryBean bean, Integer flag) {
        Pageable pageable = QPageRequest.of(bean.getPage(), bean.getSize());
        pageable = PageDataUtils.addOrderByDesc(pageable, "id");
        Pair<Integer, List<Long>> pair = getEmptyFlagAndPlanIdList(bean);
        Integer emptyFlag = pair.getKey();
        if (emptyFlag == 1) {
            return ResultBean.pageData(Lists.newArrayList(), 0);
        }
        List<Long> planIdResultList = pair.getValue();
        Specification<BpInvestigateRecord> specification = getBpInvestigateRecordSpecification(bean, flag, planIdResultList);
        Page<BpInvestigateRecord> page = recordRepository.findAll(specification, pageable);
        List<Long> taskIdList = page.stream().map(r -> r.getTaskId()).distinct().filter(Objects::nonNull).collect(Collectors.toList());
        Map<Long, Date> taskMap = taskDao.findAllById(taskIdList).stream().collect(Collectors.toMap(r -> r.getId(), r -> r.getCheckDate()));
        List<BpInvestigateRecord> recordList = page.getContent();
        List<BpInvestigateRecordBean> recordBeanList = Lists.newArrayList();
        for (BpInvestigateRecord record : recordList) {
            BpInvestigateRecordBean recordBean = new BpInvestigateRecordBean();
            BeanUtils.copyProperties(record, recordBean);
            convert(recordBean, flag);
            recordBean.setPlanDate(taskMap.get(record.getTaskId()));
            recordBeanList.add(recordBean);
        }
        return ResultBean.pageData(recordBeanList, page.getTotalElements());
    }

    private Specification<BpInvestigateRecord> getBpInvestigateRecordSpecification(BpInvestigateRecordQueryBean
                                                                                           bean, Integer flag, List<Long> planIdResultList) {
        Long currentUserId = Context.getCurrentUserId();
        return (Root<BpInvestigateRecord> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (flag == 1) {
                predicates.add(cb.equal(root.get("checkUserId"), currentUserId));
            }
            if (bean.getCheckResult() != null) {
                predicates.add(cb.like(root.get("checkResult"), "%" + bean.getCheckResult() + "%"));
            }
            if (!CollectionUtils.isEmpty(planIdResultList)) {
                CriteriaBuilder.In<Object> in = cb.in(root.get("checkPlanId"));
                for (Long aLong : planIdResultList) {
                    in.value(aLong);
                }
                predicates.add(in);
            }
            if (bean.getStartDate() != null) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("checkFinishDate"), bean.getStartDate()));
            }
            if (bean.getEndDate() != null) {
                predicates.add(cb.lessThanOrEqualTo(root.get("checkFinishDate"), bean.getEndDate()));
            }
            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };
    }

    /**
     * key: emptyFlag 1 无法查到任何数据
     * value: planIdResultList  计划id集合
     */
    private Pair<Integer, List<Long>> getEmptyFlagAndPlanIdList(BpInvestigateRecordQueryBean bean) {
        String checkName = bean.getCheckName();
        Long typeId = bean.getTypeId();
        LocalDate startDate = bean.getStartDate();
        LocalDate endDate = bean.getEndDate();
        if (startDate != null && endDate != null) {
            if (startDate.isAfter(endDate)) {
                throw new IllegalArgumentException("请选择正确的日期");
            }
        }
        List<Long> planIdList = Lists.newArrayList();
        Long planId = bean.getPlanId();
        if (planId != null) {
            planIdList.add(planId);
        }
        if (typeId != null) {
            planIdList.addAll(planRepository.findByTypeId(typeId).stream().map(r -> r.getId()).collect(Collectors.toList()));
        }
        if (!StringUtils.isEmpty(checkName)) {
            List<Long> planIds = planRepository.findIdByCheckPlanNameContains(checkName);
            if (typeId == null) {
                planIdList.addAll(planIds);
            } else {
                //取交集
                HashSet<Long> longs = new HashSet<>(planIdList);
                HashSet<Long> longs1 = new HashSet<>(planIds);
                Sets.SetView<Long> intersection = Sets.intersection(longs1, longs);
                planIdList = Lists.newArrayList(intersection);
            }
        }
        final List<Long> planIdResultList = planIdList.stream().distinct().collect(Collectors.toList());
        int emptyFlag = 0;
        if ((typeId != null || !StringUtils.isEmpty(checkName))
                && CollectionUtils.isEmpty(planIdResultList)) {
            emptyFlag = 1;
        }
        return new Pair<>(emptyFlag, planIdResultList);
    }

    /**
     * 排查记录补全: 异常总数; 异常处理结果; 排查人员; 排查类型; 排查计划名称
     * flag: 0 web; 1 app
     */
    private void convert(BpInvestigateRecordBean recordBean, Integer flag) {
        BpInvestigatePlanBean planBean = (BpInvestigatePlanBean) planService.getById(recordBean.getCheckPlanId(), flag).getData();
        //recordBean.setPlanBean(planBean);
        List<BpInvestigateRecordItem> recordItemList = recordItemDao.findByRecordId(recordBean.getId());
        //异常处理：未检也算异常总数中，异常的都处理了则为已处理
        //异常总数
        long exceptionCount = recordItemList.stream().filter(r -> RecordActionType.EX.getValue().equals(r.getAction())).count();
        long unCheckCount = recordItemList.stream().filter(r -> "未检".equals(r.getAction())).count();
        recordBean.setExceptionSum((int) (exceptionCount + unCheckCount));
        String exceptionHandleStatus = calculateExceptionHandleStatus(recordItemList, exceptionCount);
        recordBean.setExceptionHandleStatus(exceptionHandleStatus);
        //排查人员
        recordBean.setCheckUserName(baseUserDao.getRealNameById(recordBean.getCheckUserId()));
        recordBean.setTypeName(planBean.getTypeName());
        recordBean.setCheckPlanName(planBean.getCheckPlanName());
    }

    @Override
    public String calculateExceptionHandleStatus(List<BpInvestigateRecordItem> recordItemList, long exceptionCount) {
        //异常处理
        String exceptionHandleStatus = "无需处理";
        for (BpInvestigateRecordItem recordItem : recordItemList) {
            if (RecordActionType.EX.getValue().equals(recordItem.getAction()) && !"已处理".equals(recordItem.getRepairStatus())) {
                exceptionHandleStatus = "等待处理";
                break;
            }
        }
        if (exceptionCount > 0 && "无需处理".equals(exceptionHandleStatus)) {
            exceptionHandleStatus = "已处理";
        }
        return exceptionHandleStatus;
    }

    @Override
    public void excelExport(BpInvestigateRecordQueryBean bean, HttpServletRequest request, HttpServletResponse
            response) {
        Pair<Integer, List<Long>> pair = getEmptyFlagAndPlanIdList(bean);
        Integer emptyFlag = pair.getKey();
        if (emptyFlag == 1) {
            throw new IllegalArgumentException("当前条件查不到任何数据");
        }
        List<Long> planIdTempList = pair.getValue();
        Specification<BpInvestigateRecord> specification = getBpInvestigateRecordSpecification(bean, 0, planIdTempList);
        List<BpInvestigateRecord> recordList = recordRepository.findAll(specification);
        List<BpInvestigateRecordBean> recordBeanList = recordList.stream().map(r -> {
            BpInvestigateRecordBean recordBean = new BpInvestigateRecordBean();
            BeanUtils.copyProperties(r, recordBean);
            convert(recordBean, 0);
            return recordBean;
        }).collect(Collectors.toList());
        Map<Long, String> departMap = getDepartMap(recordList);
        List<Long> planIdList = recordList.stream().map(r -> r.getCheckPlanId()).distinct().collect(Collectors.toList());
        Map<Long, String> checkWayMap = planRepository.findAllById(planIdList).stream().collect(Collectors.toMap(r -> r.getId(), r -> r.getCheckWay()));
        List<BpInvestigateRecordExport> exportList = recordBeanList.stream().map(r -> new BpInvestigateRecordExport(r, checkWayMap.get(r.getCheckPlanId()),
                        departMap.get(r.getDutyDepartId()))).sorted(Comparator.comparing(BpInvestigateRecordExport::getId).reversed())
                .collect(Collectors.toList());
        //1.xlsx 文件会打不开 2.swagger测试会有中文乱码问题ignore
        String fileName = "排查记录.xls";
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        HSSFWorkbook hwb = null;
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            fileName = FileUtil.getEncodeFileName(request, fileName);
            response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
            List<String> cellNames = getCellName();
            Pair<HSSFWorkbook, HSSFSheet> workbookPair = PoiUtil.getPoi("排查记录", cellNames);
            addRecordData(exportList, workbookPair);
            hwb = workbookPair.getKey();
            hwb.write(outputStream);
        } catch (IOException e) {
            log.warn("排查记录excel导出失败：" + e.getMessage());
            throw new IllegalArgumentException("excel导出失败，请联系系统管理员");
        } finally {
            if (hwb != null) {
                try {
                    hwb.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Map<Long, String> getDepartMap(List<BpInvestigateRecord> recordList) {
        List<Long> departIdList = recordList.stream().map(r -> r.getDutyDepartId()).distinct().collect(Collectors.toList());
        return bpDepartDao.findAllById(departIdList).stream().collect(Collectors.toMap(r -> r.getId(), r -> r.getName()));
    }

    private void addRecordData
            (List<BpInvestigateRecordExport> exportList, Pair<HSSFWorkbook, HSSFSheet> pair) {
        HSSFSheet sheet = pair.getValue();
        for (int i = 0; i < exportList.size(); i++) {
            BpInvestigateRecordExport export = exportList.get(i);
            HSSFRow row = sheet.createRow(i + 1);
            row.createCell(0).setCellValue(export.getId());
            row.createCell(1).setCellValue(export.getCheckPlanName());
            row.createCell(2).setCellValue(export.getTypeName());
            row.createCell(3).setCellValue(export.getCheckWay());
            row.createCell(4).setCellValue(export.getCheckFinishDate().toString());
            row.createCell(5).setCellValue(export.getCheckUserName());
            row.createCell(6).setCellValue(export.getDutyDepartName());
            row.createCell(7).setCellValue(export.getCheckResult());
            row.createCell(8).setCellValue(export.getExceptionHandleStatus());
        }
    }

    private List<String> getCellName() {
        List<String> list = new ArrayList<>();
        list.add("排查单编号");
        list.add("排查名称");
        list.add("排查类型");
        list.add("排查方式");
        list.add("排查完成时间");
        list.add("排查人员");
        list.add("受检单位");
        list.add("排查结果");
        list.add("异常处理");
        return list;
    }


    @Override
    public ResultBean exceptionHandle(Long id) {
        // 兼容今日和历史页面
        boolean isHistory = false;
        BpInvestigateRecord record;
        Optional<BpInvestigateRecord> recordOptional = recordRepository.findById(id);
        if (recordOptional.isPresent()) {
            record = recordOptional.get();
        } else {
            isHistory = true;
            record = investigateHistoryMapper.getRecordById(id);
        }

        if (null == record) {
            throw new IllegalArgumentException("此数据不存在或已被删除");
        }
        BpInvestigateRecordBean recordBean = new BpInvestigateRecordBean();
        BeanUtils.copyProperties(record, recordBean);
        //人员
        recordBean.setCheckUserName(baseUserDao.getBaseUserNameById(record.getCheckUserId()));
        List<BpInvestigateRecordItem> itemList;
        if (isHistory) {
            itemList = investigateHistoryMapper.getHistoryItemByRecordId(record.getId());
        }else {
            itemList = recordItemDao.findByRecordId(record.getId());
        }
        Long checkPlanId = record.getCheckPlanId();
        planRepository.findById(checkPlanId).ifPresent(r -> recordBean.setCheckPlanName(r.getCheckPlanName()));
        List<Long> itemIdList = itemList.stream().map(r -> r.getCheckItemId()).distinct().collect(Collectors.toList());
        Map<Long, BpSafeTableItem> tableItemMap = tableItemDao.findAllById(itemIdList).stream().collect(Collectors.toMap(r -> r.getId(), r -> r));
        String autograph="";
        BaseConfig config = baseConfigService.findFirstConfig(BaseConfigCodes.AUTOGRAPH);
        if (config != null && config.getValue().equals("开启")&&recordBean.getCheckUserId()!=null) {
            autograph= baseUserDao.getAutograph(recordBean.getCheckUserId());
        }
        List<BpInvestigateRecordItemBean> itemBeanList = getBpInvestigateRecordItemBeans(itemList, tableItemMap,autograph);
        itemBeanList = itemBeanList.stream().filter(r -> "异常".equals(r.getAction()) ||
                "未检".equals(r.getAction())).collect(Collectors.toList());
        recordBean.setItemBeanList(itemBeanList);
        return ResultBean.success(recordBean);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultBean repair(Long recordId, Long checkItemId) {
        boolean isHistory = false;
        BpInvestigateRecord record = recordRepository.findById(recordId).orElse(null);
        if (null == record) {
            isHistory = true;
            record = investigateHistoryMapper.getRecordById(recordId);
        }
        if (null == record) {
            throw new IllegalArgumentException("此数据不存在");
        }
        List<BpInvestigateRecordItem> recordItemList = null;
        if (isHistory) {
            recordItemList = investigateHistoryMapper.getHistoryItemByRecordId(recordId);
        }else {
            recordItemList = recordItemDao.findByRecordId(recordId);
        }
        for (BpInvestigateRecordItem recordItem : recordItemList) {
            if (recordItem.getCheckItemId().equals(checkItemId)) {
                if (!"未整改".equals(recordItem.getRepairStatus())) {
                    return ResultBean.fail(101, "当前状态不可整改");
                }
                recordItem.setRepairStatus("已处理");
                if (isHistory) {
                    investigateHistoryMapper.updateRecordItemRepairStatus(recordItem.getId(), recordItem.getRepairStatus());
                }else {
                    recordItemDao.save(recordItem);
                }
            }
        }
        List<String> repairStatus = recordItemList.stream().map(BpInvestigateRecordItem::getRepairStatus).collect(Collectors.toList());
        updateSummaryRepairStatus(repairStatus, record.getTaskId(), isHistory);
        return ResultBean.defaultSuccessResult();
    }

    private void updateSummaryRepairStatus(List<String> repairStatus,Long taskId, boolean isHistory) {
        if (!repairStatus.contains("未整改")) {
            if (isHistory) {
                investigateHistoryMapper.updateRepairStatusByTaskId("已处理", taskId);
            }else {
                summaryMapper.updateRepairStatusByTaskId("已处理", taskId);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void repairV2(Long itemId) {
        // item 表没有则从item_his中取
        BpInvestigateRecordItem recordItem = recordItemDao.findById(itemId).orElse(null);
        if (null == recordItem) {
            investigateHistoryMapper.updateRecordItemRepairStatus(itemId,"已处理");
        }else {
            recordItem.setId(itemId);
            recordItem.setRepairStatus("已处理");
            recordItemDao.save(recordItem);
        }
        // 更新summary的异常处理状态
        bpInvestigateTaskSummaryService.updateSummaryRepairStatusV2(itemId);
    }

    /**
     * 更改计划状态，并通知风险评估模块重新计算风险等级
     *
     * @param itemId
     */
    @Override
    public void changePlanInvalid(Long itemId, String url) {
        boolean isHistory = false;
        Optional<BpInvestigateRecordItem> itemOptional = recordItemDao.findById(itemId);
        BpInvestigateRecordItem item = null;
        if (!itemOptional.isPresent()) {
            isHistory = true;
            item = investigateHistoryMapper.getHistoryItemById(itemId);
        }else {
            item = itemOptional.get();
        }
        BpInvestigateRecord record = !isHistory ? recordRepository.findById(item.getRecordId()).get() :
                investigateHistoryMapper.getRecordById(item.getRecordId());
        // 更改排查计划失效状态，通知风险评估重新计算风险
        if (!ObjectUtils.isEmpty(record)){
            BpInvestigatePlan plan = planRepository.findById(record.getCheckPlanId()).get();
            long rectifyCount = planRepository.countUnRectifyRecord(plan.getId()) + planRepository.countUnRectifyRecordHistory(plan.getId());
            if (rectifyCount < 1) {
                plan.setInvalidReason(Constant.EMPTY_STR);
                plan.setInvalidFlag(Constant.COMMON_SWITCH_OFF);
                planRepository.save(plan);
            }
        }
        /**
         * 查询计划下异常任务。异常任务：
         * 1.上报异常，未开始隐患整改
         *  item的repair_status字段为未处理
         * 2.上报异常，开始隐患整改，但整改未完成 (今日+历史)
         *  特征1：workflow_task中status字段为0（旧版本流程引擎）
         *  特征2：item的wf_process_status字段不为空且不是 完成 || 已终止，（新版本流程引擎）
         */
//        Long evalItemId = !isHistory ? bpInvestigateRecordItemDao.getPointEvalItemIdById(item.getId()) :
//                bpInvestigateRecordItemDao.getPointEvalItemIdByHistoryId(item.getId());
//        if (evalItemId != null) {
//            evaluationBusinessService.recalculateRealRiskLevel(ControlRiskLevelType.EFFICIENT.getValue(), new RiskItemEvalCountRecordVo("有效", url, evalItemId));
//        }
    }

    @Override
    public List<DeleteInvestigateRecordDto> getFinishNewSourceTask(Long lastRecordId) {
        return bpInvestigateRecordMapper.getFinishNewSourceTask(lastRecordId);
    }

}


